#ifndef PW_PBL_TUPLE_HPP
#define PW_PBL_TUPLE_HPP

#include "Concepts/Pack.hpp"
#include "Self.hpp"

namespace pw_pbl::_tuple
{
	template <typename T>
	constexpr bool is_zst = std::is_empty_v<T>;

	template <typename T>
	struct null_instance
	{
		static constexpr T obj{};

		template <typename Self,
				  typename MAYBECONST = std::conditional_t<std::is_const_v<std::remove_reference_t<Self>>, const T, T>,
				  typename OUT = std::conditional_t<std::is_rvalue_reference_v<Self &&>, MAYBECONST &&, MAYBECONST &>>
		static constexpr OUT get(std::type_identity_t<Self &> self)
		{
			if consteval
			{
				return static_cast<OUT>(const_cast<T &>(obj));
			}
			else
			{
				return static_cast<OUT>(*reinterpret_cast<MAYBECONST *>(&self));
			}
		}
	};

	template <typename Self, typename T>
	struct null_tag;

	template <size_t ID, typename T>
	struct ele
	{
		T v;

		using raw_type = T;

		template <typename Self>
		constexpr ttForwardApply<Self &&, T> get(this Self &&self) { return std::forward<Self>(self).v; }

		template <typename NT>
		constexpr void set(NT &&nv) requires(!std::is_reference_v<T>) { v = std::forward<NT>(nv); }
	};

	/// 为解决相同空类型占用空间，添加索引和结构类型自身，强制使类型惟一
	template <typename Self, size_t ID, typename T>
	struct ele<ID, null_tag<Self, T>>
	{
		constexpr ele() requires std::is_default_constructible_v<T> = default;
		constexpr ele(T) {}

		using raw_type = T;

		template <typename Sf>
		constexpr ttForwardApply<Sf &&, T> get(this Sf &&sf) { return null_instance<T>::template get<Sf>(sf); }

		constexpr void set(const T &) {}

		template <size_t NID, typename NSelf>
		constexpr operator ele<NID, null_tag<NSelf, T>>() const { return {get()}; } //< 空元素位置或所在类型变动仍应视为同一元素以方便元素批量迭代
	};

	template <typename NT, typename OUT = std::conditional_t<std::move_constructible<std::remove_cvref_t<NT>>, NT, const std::remove_reference_t<NT> &>>
	constexpr OUT &&maynotmove(NT &&nt) { return static_cast<OUT &&>(nt); }

	/// 元组整体赋值时，元素模拟结构字段赋值方式
	template <typename FLD, typename SRC>
	concept fldAssignable = std::is_assignable_v<FLD &, SRC &&> || std::is_assignable_v<FLD &, const std::remove_reference_t<SRC> &>;

	/// 元组整体赋值时，元素模拟结构字段赋值方式
	template <typename FLD, typename SRC>
	constexpr decltype(auto) fld_assign(SRC &&src)
	{
		if constexpr (std::is_assignable_v<FLD &, SRC &&>)
			return std::forward<SRC>(src);
		else
			return static_cast<const std::remove_reference_t<SRC> &>(src);
	}

	template <typename... T>
	struct sparse;

	template <size_t... ID, typename... T>
	struct sparse<ele<ID, T>...> : public ele<ID, T>...
	{
		template <size_t IID, typename Self, typename IT = T...[IID]>
		constexpr ttForwardApply<Self &&, typename ele<IID, IT>::raw_type> get(this Self &&self) { return forward_cast<Self, ele<IID, IT>>(self).get(); }

		template <typename Self>
		constexpr decltype(auto) apply(this Self &&self, auto f) { return std::move(f)(forward_cast<Self, ele<ID, T>>(self).get()...); }

		template <typename... NT, typename Self, typename TRAITS = ttTupleTraits<std::remove_cvref_t<Self>>> requires(!std::same_as<typename TRAITS::type, sparse>)
		constexpr TRAITS::template append<std::unwrap_ref_decay_t<NT>...> add(this Self &&self, NT &&...nt)
		{
			return {{forward_cast<Self, ele<ID, T>>(self)..., {maynotmove(std::forward<NT>(nt))}...}};
		}

		template <typename TUPLE, typename DECAY = std::remove_cvref_t<TUPLE>, typename = std::enable_if_t<(... && fldAssignable<typename ele<ID, T>::raw_type, ttForwardApply<TUPLE &&, std::tuple_element_t<ID, DECAY>>>)>>
		constexpr void assign(TUPLE &&tup); // 为了使std::get重载可见所以在体外定义

		template <typename... Args> requires(... && std::is_assignable_v<typename ele<ID, T>::raw_type &, Args &&>)
		constexpr void assign(Args &&...args) { (static_cast<ele<ID, T> &>(*this).set(std::forward<Args>(args)), ...); }

		template <typename Self, typename TUPLE, typename TRAITS = ttTupleTraits<std::remove_cvref_t<Self>>>
		constexpr decltype(auto) concat(this Self &&self, TUPLE &&tup); // 为了使std::get重载可见所以在体外定义
	};

	template <typename Self>
	struct zst_base
	{
		template <size_t ID, typename IT>
		using elet = ele<ID, std::conditional_t<is_zst<IT>, null_tag<Self, IT>, IT>>;

		template <typename... T>
		using type = ttEachApplyWithId<sparse, elet, T...>;
	};
} // namespace pw_pbl::_tuple

namespace pw_pbl
{
	/// 标准元组
	/// @note 无构造函数，使用纯结构构造{{{t0},{t1},...}}
	/// @note 如需要自动推导类型构造可用make_tuple(t0, t1, ...)或Tuple<>{}.add(t0, t1, ...)的形式，推导类型默认为值类型，除非是reference_wrapper修饰的才为引用
	template <typename... T>
	struct Tuple : public ttEachApplyWithId<_tuple::sparse, _tuple::ele, T...>
	{
		using base = ttEachApplyWithId<_tuple::sparse, _tuple::ele, T...>;

		template <size_t ID, typename Self, typename OT = T...[ID]>
		constexpr ttForwardApply<Self &&, OT> get(this Self &&self) { return forward_cast<Self, _tuple::ele<ID, OT>>(self).v; } // 无空元素优化重载

		template <typename TUPLE>
		constexpr void operator=(TUPLE &&tup) requires requires { this->assign(std::forward<TUPLE>(tup)); } { this->assign(std::forward<TUPLE>(tup)); }
	};

	/// 空对象占用空间优化的元组
	/// @note 相比标准元组，空元素类型不占用本对象空间，sizeof(ZoTuple<std::tuple<>, std::tuple<>, std::tuple<>, ZoTuple<std::tuple<>, std::tuple<>, std::tuple<>>) == 1而不是6
	/// @note 相比标准元组，仅略微增加编译时间
	/// @note 获取的元素为空类型时，返回的引用不保证地址惟一，不符合标准!!!
	/// @note 无构造函数，使用纯结构构造{{{t0},{t1},...}}
	/// @note 如需要自动推导类型构造可用make_zo_tuple(t0, t1, ...)或ZoTuple<>{}.add(t0, t1, ...)的形式，推导类型默认为值类型，除非是reference_wrapper修饰的才为引用
	template <typename... T>
	struct ZoTuple : public _tuple::zst_base<ZoTuple<T...>>::template type<T...>
	{
		using base = _tuple::zst_base<ZoTuple<T...>>::template type<T...>;

		template <typename TUPLE>
		constexpr void operator=(TUPLE &&tup) requires requires { this->assign(std::forward<TUPLE>(tup)); } { this->assign(std::forward<TUPLE>(tup)); }
	};

	template <typename... Args>
	constexpr Tuple<std::unwrap_ref_decay_t<Args>...> make_tuple(Args &&...args) { return {{{_tuple::maynotmove(std::forward<Args>(args))}...}}; }

	template <typename... Args>
	constexpr ZoTuple<std::unwrap_ref_decay_t<Args>...> make_zo_tuple(Args &&...args) { return {{{_tuple::maynotmove(std::forward<Args>(args))}...}}; }

	template <typename... Args>
	constexpr Tuple<Args &&...> forward_as_tuple(Args &&...args) { return {{{std::forward<Args>(args)}...}}; }

	template <typename... Args>
	constexpr Tuple<Args &...> tie(Args &...args) { return {{{args}...}}; }

	using std::apply;
	using std::ignore;
	using std::make_from_tuple;
} // namespace pw_pbl

namespace std
{
	template <size_t ID, typename... T>
	constexpr std::type_identity_t<T...[ID]> &&get(pw_pbl::Tuple<T...> &&tup) { return std::move(tup).template get<ID>(); }

	template <size_t ID, typename... T>
	constexpr const std::type_identity_t<T... [ID]> &get(const pw_pbl::Tuple<T...> &tup) { return tup.template get<ID>(); }

	template <size_t ID, typename... T>
	constexpr std::type_identity_t<T...[ID]> &&get(pw_pbl::ZoTuple<T...> &&tup)
	{
		return std::move(tup).template get<ID>();
	}

	template <size_t ID, typename... T>
	constexpr const std::type_identity_t<T... [ID]> &get(const pw_pbl::ZoTuple<T...> &tup) { return tup.template get<ID>(); }
} // namespace std

namespace pw_pbl::_tuple
{ // 这部分需要操作tuple like对象，需要用到std::get，放在其重载定义之后使其可见

	template <size_t... ID, typename... T>
	template <typename TUPLE, typename, typename>
	constexpr void sparse<ele<ID, T>...>::assign(TUPLE &&tup) { (static_cast<ele<ID, T> &>(*this).set(fld_assign<T>(std::get<ID>(std::forward<TUPLE>(tup)))), ...); }

	template <size_t... ID, typename... T>
	template <typename Self, typename TUPLE, typename TRAITS>
	constexpr decltype(auto) sparse<ele<ID, T>...>::concat(this Self &&self, TUPLE &&tup)
	{
		using decay_tup = std::remove_cvref_t<TUPLE>;
		return [&self, &tup]<size_t... NID>(std::index_sequence<NID...>) -> TRAITS::template append<std::tuple_element_t<NID, decay_tup>...> {
			return {{forward_cast<Self, ele<ID, T>>(self)..., {maynotmove(std::get<NID>(std::forward<TUPLE>(tup)))}...}};
		}(std::make_index_sequence<std::tuple_size_v<decay_tup>>{});
	}

	struct ttindex
	{
		size_t tup;
		size_t in_tup;
	};

	/// 元组的元组，用于tuple_cat的实现
	/// @tparam T 元组类型，去掉cvref修饰后必须是tuple like对象
	template <typename... T>
	struct TupleTuple : public ttEachApplyWithId<sparse, ele, T...>
	{
		static constexpr size_t ESizes[sizeof...(T)] = {std::tuple_size_v<std::remove_cvref_t<T>>...};

		static constexpr size_t ETotal = [] {size_t t = 0; for(auto i:ESizes) t+=i;return t; }();

		static constexpr std::array<ttindex, ETotal> EIndex = [] {
			std::array<ttindex, ETotal> out = {};
			ttindex *p = out.begin();
			for (size_t i = 0; i < sizeof...(T); i++)
				for (size_t j = 0, sz = ESizes[i]; j < sz; j++)
					*p++ = ttindex{.tup = i, .in_tup = j};
			return out;
		}();

		template <size_t ID>
		using tup_type = T...[EIndex[ID].tup];

		template <size_t ID>
		using ele_type = std::tuple_element_t<EIndex[ID].in_tup, std::remove_cvref_t<tup_type<ID>>>;

		template <size_t ID, typename Self, typename TUP = ttForwardApply<Self &&, tup_type<ID>>>
		constexpr ttForwardApply<TUP, ele_type<ID>> get(this Self &&self)
		{
			return std::get<EIndex[ID].in_tup>(static_cast<TUP>(forward_cast<Self, ele<EIndex[ID].tup, tup_type<ID>>>(self).v));
		}

		template <template <typename...> class TUPLE = Tuple, size_t... ID, typename Self>
		constexpr TUPLE<ele_type<ID>...> make_from_ids(this Self &&self, std::index_sequence<ID...>)
		{
			return {{{maynotmove(std::forward<Self>(self).template get<ID>())}...}};
		}
	};
} // namespace pw_pbl::_tuple

namespace pw_pbl
{
	template <typename... TUP>
	constexpr decltype(auto) tuple_cat(TUP &&...tup)
	{
		using TUPLE = _tuple::TupleTuple<TUP &&...>;
		return TUPLE{{{std::forward<TUP>(tup)}...}}.make_from_ids(std::make_index_sequence<TUPLE::ETotal>{});
	}

	template <typename... TUP>
	constexpr decltype(auto) zo_tuple_cat(TUP &&...tup)
	{
		using TUPLE = _tuple::TupleTuple<TUP &&...>;
		return TUPLE{{{std::forward<TUP>(tup)}...}}.template make_from_ids<ZoTuple>(std::make_index_sequence<TUPLE::ETotal>{});
	}
} // namespace pw_pbl

#endif // PW_PBL_TUPLE_HPP
